﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Xml.Linq;
using System.Drawing;
using System.Windows.Forms;
using ZedGraph;
using System.Linq;
using System.Text;

namespace POSProgram
{
    public partial class MDIParent : Form
    {
        public static int p = 4;
        public static int z = 4;
        public bool changed = true;
        source so;
        ZedGraphControl[] zg = { new ZedGraphControl(), new ZedGraphControl(), new ZedGraphControl() };

        public MDIParent()
        {
            InitializeComponent();
            InitializeGraph();
            InitializeForms();
        }

        private void InitializeGraph()
        {
            //Cycklogramm
            zg[0].Dock = DockStyle.Fill;
            zg[0].Location = new Point(0, 0);
            zg[0].GraphPane.Title.Text = "Циклограмма";
            zg[0].GraphPane.XAxis.Title.Text = "День";
            zg[0].GraphPane.YAxis.Title.Text = "Захватка";
            zg[0].GraphPane.XAxis.Scale.MajorStep = 5;
            zg[0].GraphPane.XAxis.Scale.MinorStep = 1;
            zg[0].GraphPane.YAxis.Scale.MajorStep = 1;
            zg[0].GraphPane.YAxis.Scale.MinorStep = 1;
            zg[0].GraphPane.Legend.IsVisible = false;
            zg[0].GraphPane.IsFontsScaled = false;
            zg[0].GraphPane.YAxis.MajorGrid.DashOn = 6;
            zg[0].GraphPane.YAxis.MajorGrid.DashOff = 3;
            zg[0].GraphPane.XAxis.MajorGrid.Color = Color.Gray;
            zg[0].GraphPane.XAxis.MinorGrid.Color = Color.Gray;
            zg[0].GraphPane.YAxis.MajorGrid.Color = Color.Gray;
            zg[0].GraphPane.XAxis.MajorGrid.IsVisible = true;
            zg[0].GraphPane.XAxis.MinorGrid.IsVisible = true;
            zg[0].GraphPane.YAxis.MajorGrid.IsVisible = true;
            zg[0].PointValueEvent += new ZedGraphControl.PointValueHandler(zedGraph_PointValueEvent);
            zg[0].ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(zedGraph_ContextMenuBuilder);
            //Workers
            zg[1].Dock = DockStyle.Fill;
            zg[1].Location = new Point(0, 0);
            zg[1].GraphPane.Title.Text = "График движения рабочей силы";
            zg[1].GraphPane.XAxis.Title.Text = "День";
            zg[1].GraphPane.YAxis.Title.Text = "Рабочие";
            zg[1].GraphPane.XAxis.Scale.MajorStep = 5;
            zg[1].GraphPane.XAxis.Scale.MinorStep = 1;
            zg[1].GraphPane.Legend.IsVisible = false;
            zg[1].GraphPane.IsFontsScaled = false;
            zg[1].GraphPane.XAxis.MajorGrid.DashOn = 6;
            zg[1].GraphPane.XAxis.MajorGrid.DashOff = 3;
            zg[1].GraphPane.XAxis.MinorGrid.DashOn = 1;
            zg[1].GraphPane.XAxis.MinorGrid.DashOff = 2;
            zg[1].GraphPane.YAxis.MajorGrid.DashOn = 6;
            zg[1].GraphPane.YAxis.MajorGrid.DashOff = 3;
            zg[1].GraphPane.YAxis.MinorGrid.DashOn = 1;
            zg[1].GraphPane.YAxis.MinorGrid.DashOff = 2;
            zg[1].GraphPane.XAxis.MajorGrid.Color = Color.Gray;
            zg[1].GraphPane.XAxis.MinorGrid.Color = Color.Gray;
            zg[1].GraphPane.YAxis.MajorGrid.Color = Color.Gray;
            zg[1].GraphPane.YAxis.MinorGrid.Color = Color.Gray;
            zg[1].GraphPane.XAxis.MajorGrid.IsVisible = true;
            zg[1].GraphPane.XAxis.MinorGrid.IsVisible = true;
            zg[1].GraphPane.YAxis.MajorGrid.IsVisible = true;
            zg[1].GraphPane.YAxis.MinorGrid.IsVisible = true;
            zg[1].PointValueEvent += new ZedGraphControl.PointValueHandler(zedGraph_PointValueEvent);
            zg[1].ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(zedGraph_ContextMenuBuilder);
            //Cash
            zg[2].Dock = DockStyle.Fill;
            zg[2].Location = new Point(0, 0);
            zg[2].GraphPane.Title.Text = "График освоения средств";
            zg[2].GraphPane.XAxis.Title.Text = "День";
            zg[2].GraphPane.YAxis.Title.Text = "Сумма (тыс.руб.)";
            zg[2].GraphPane.XAxis.Scale.MajorStep = 10;
            zg[2].GraphPane.XAxis.Scale.MinorStep = 2;
            zg[2].GraphPane.Legend.IsVisible = false;
            zg[2].GraphPane.IsFontsScaled = false;
            zg[2].GraphPane.XAxis.MajorGrid.DashOn = 6;
            zg[2].GraphPane.XAxis.MajorGrid.DashOff = 3;
            zg[2].GraphPane.XAxis.MinorGrid.DashOn = 1;
            zg[2].GraphPane.XAxis.MinorGrid.DashOff = 2;
            zg[2].GraphPane.YAxis.MajorGrid.DashOn = 6;
            zg[2].GraphPane.YAxis.MajorGrid.DashOff = 3;
            zg[2].GraphPane.YAxis.MinorGrid.DashOn = 1;
            zg[2].GraphPane.YAxis.MinorGrid.DashOff = 2;
            zg[2].GraphPane.XAxis.MajorGrid.Color = Color.Gray;
            zg[2].GraphPane.XAxis.MinorGrid.Color = Color.Gray;
            zg[2].GraphPane.YAxis.MajorGrid.Color = Color.Gray;
            zg[2].GraphPane.YAxis.MinorGrid.Color = Color.Gray;
            zg[2].GraphPane.XAxis.MajorGrid.IsVisible = true;
            zg[2].GraphPane.XAxis.MinorGrid.IsVisible = true;
            zg[2].GraphPane.YAxis.MajorGrid.IsVisible = true;
            zg[2].GraphPane.YAxis.MinorGrid.IsVisible = true;
            zg[2].PointValueEvent += new ZedGraphControl.PointValueHandler(zedGraph_PointValueEvent);
            zg[2].ContextMenuBuilder += new ZedGraphControl.ContextMenuBuilderEventHandler(zedGraph_ContextMenuBuilder);
        }

        private string zedGraph_PointValueEvent(ZedGraphControl sender, GraphPane pane, CurveItem curve, int iPt)
        {
            PointPair point = curve[iPt];
            string result = string.Empty;
            if (pane.Title.Text == "Циклограмма")
                result = string.Format("{0}\nЗахв: {2}\nДень: {1}", curve.Label.Text, point.X, point.Y);
            else if (pane.Title.Text == "График движения рабочей силы")
                result = string.Format("Рабочих: {1}\nДень: {0}", point.X, point.Y);
            else if (pane.Title.Text == "График освоения средств")
                result = string.Format("Сумма: {1}\nДень: {0}", point.X, point.Y);
            return result;
        }

        private void zedGraph_ContextMenuBuilder(ZedGraphControl sender, ContextMenuStrip menuStrip, Point mousePt,
            ZedGraphControl.ContextMenuObjectState objState)
        {
            menuStrip.Items[0].Text = "Копировать";
            menuStrip.Items[1].Text = "Сохранить как картинку…";
            menuStrip.Items[4].Text = "Показывать значения в точках…";
            menuStrip.Items[6].Text = "Отменить увеличение/уменьшение";
            menuStrip.Items.RemoveAt(7);
            menuStrip.Items.RemoveAt(5);
            menuStrip.Items.RemoveAt(3);
            menuStrip.Items.RemoveAt(2);
        }

        private void InitializeForms()
        {
            string[] titles = new string[] { "Циклограмма", "График движения рабочей силы", "График освоения средств", "Исходные данные", "Проект" };
            Form fm;
            for (int i = 0; i < 4; i++)
            {
                if (i == 3)
                {
                    so = new source(this);
                    so.MdiParent = this;
                    so.FormClosing += new FormClosingEventHandler(DontClose);
                    so.Show();
                }
                else
                {
                    fm = new Form();
                    fm.ClientSize = new System.Drawing.Size(450, 350);
                    fm.MdiParent = this;
                    fm.ShowIcon = false;
                    fm.Text = titles[i];
                    fm.FormClosing += new FormClosingEventHandler(DontClose);
                    fm.Controls.Add(zg[i]);
                    fm.Show();
                }
            }
        }

        void DontClose(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                Form fm = (Form)sender;
                e.Cancel = true;
                if (fm.IsMdiChild)
                    fm.MdiParent = null;
                else
                    fm.MdiParent = this;
            }
        }

        private void OpenFile(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            openFileDialog.Filter = "POS файл (*.pos)|*.pos|Все файлы (*.*)|*.*";
            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                XDocument xdoc = XDocument.Load(openFileDialog.FileName);
                string date = xdoc.Root.Element("date").Value;
                string appver = xdoc.Root.Element("version").Value;
                string hash = xdoc.Root.Element("guid").Value;
                string type = xdoc.Root.Element("table").Attribute("type").Value;
                List<string> li1 = new List<string>();
                List<string[]> li2 = new List<string[]>();

                if (hash != Guid(date + appver + xdoc.Root.Element("table")))
                {
                    if (MessageBox.Show("Файл был изменён в сторонней программе.\nПродолжить?", "Внимание!", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Cancel)
                        return;
                }

                so.toolStripComboBox1.SelectedIndex = int.Parse(type);
                so.toolStripComboBox2.SelectedIndex = int.Parse(xdoc.Root.Element("table").Attribute("parts").Value) - 2;
                so.toolStripComboBox3.SelectedIndex = int.Parse(xdoc.Root.Element("table").Attribute("processes").Value) - 2;

                foreach (var proc in xdoc.Root.Element("table").Elements())
                {
                    li1.Add(proc.Attribute("name").Value);
                    li2.Add(proc.Value.Split('-'));
                }

                if (type == "2")
                {
                    string[] seq = xdoc.Root.Element("table").Attribute("sequence").Value.Split('-');
                    for (int i = 0; i < z; i++)
                        so.dataGridView1.Columns[i + 1].HeaderText = seq[i];
                }

                for (int i = 0; i < p; i++)
                {
                    so.dataGridView1[0, i].Value = li1[i];
                    for (int j = 1; j <= li2[0].Length; j++)
                        so.dataGridView1[j, i].Value = li2[i][j - 1];
                }
            }
        }

        private void SaveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            saveFileDialog.Filter = "POS файл (*.pos)|*.pos|Все файлы (*.*)|*.*";
            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                string day = "";
                string date = DateTime.Now.ToString();
                string appver = Application.ProductVersion;
                XElement _tab = new XElement("table");
                _tab.Add(new XAttribute("type", so.toolStripComboBox1.SelectedIndex));
                _tab.Add(new XAttribute("processes", p));
                _tab.Add(new XAttribute("parts", z));
                if (so.toolStripComboBox1.SelectedIndex == 2)
                {
                    for (int i = 1; i <= z; i++)
                        day += so.dataGridView1.Columns[i].HeaderText + '-';
                    _tab.Add(new XAttribute("sequence", day.Remove(day.Length - 1)));
                }

                for (int i = 0; i < p; i++)
                {
                    day = "";
                    for (int j = 1; j < so.dataGridView1.ColumnCount; j++)
                        day += so.dataGridView1[j, i].Value + "-";
                    day = day.Remove(day.Length - 1);
                    _tab.Add(new XElement("process", new XAttribute("name", so.dataGridView1[0, i].Value), day));
                }

                XDocument xdoc = new XDocument(
                    new XElement("POSFile",
                        new XElement("date", date),
                        new XElement("version", appver),
                        new XElement("guid", Guid(date + appver + _tab)),
                        new XElement(_tab)));
                xdoc.Save(saveFileDialog.FileName);
            }
        }

        string Guid(object obj)
        {
            MD5 md5Hasher = MD5.Create();
            StringBuilder sBuilder = new StringBuilder();
            byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes("x2" + obj.ToString()));
            for (int i = 0; i < data.Length; i++)
                sBuilder.Append(data[i].ToString("x2"));
            Guid g = new Guid(sBuilder.ToString());
            return g.ToString();
        }

        private void ExitToolsStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void CutToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void CopyToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void PasteToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void ToolBarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolStrip.Visible = toolBarToolStripMenuItem.Checked;
        }

        private void StatusBarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            statusStrip.Visible = statusBarToolStripMenuItem.Checked;
        }

        private void CascadeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LayoutMdi(MdiLayout.Cascade);
        }

        private void TileVerticalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LayoutMdi(MdiLayout.TileHorizontal);
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            try
            {
                solver solv = new solver();
                var cp = new List<float[]>();
                float w;
                float[,] mas = new float[p, z + 1];
                float[,] day = new float[p, z + 1];
                float[][] wm = new float[3][] { new float[p * 2], new float[p * 2], new float[p * 2] };

                ToMassiv(ref day, ref wm);
                solv.matrix(day, ref mas, ref cp);
                w = solv.workers(ref wm, mas);
                Drawing(wm, mas, cp, w);
                toolStripStatusLabel.Text = "Общая продолжительность " + mas[p - 1, z] + " дней.";
                changed = false;
            }
            catch (Exception)
            {
                toolStripStatusLabel.Text = "Ошибка расчёта!";
            }
        }

        private void ToMassiv(ref float[,] day, ref float[][] wm)
        {
            switch (so.toolStripComboBox1.SelectedIndex)
            {
                case 0:
                    for (int i = 0; i < p; i++)
                    {
                        for (int j = 0; j < z; j++)
                            day[i, j] = Convert.ToSingle(so.dataGridView1.Rows[0].Cells[1].Value);

                        wm[1][i] = Convert.ToSingle(so.dataGridView1.Rows[0].Cells[2].Value); // Рабочие
                        wm[2][i] = Convert.ToSingle(so.dataGridView1.Rows[0].Cells[3].Value); // Стоимость
                    }
                    break;
                case 1:
                    for (int i = 0; i < p; i++)
                    {
                        for (int j = 0; j < z; j++)
                            day[i, j] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[1].Value);

                        wm[1][i] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[2].Value);
                        wm[2][i] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[3].Value);
                    }
                    break;
                case 2:
                    for (int i = 0; i < p; i++)
                    {
                        for (int j = 0; j < z; j++)
                            day[i, j] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[j + 1].Value);

                        wm[1][i] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[z + 1].Value);
                        wm[2][i] = Convert.ToSingle(so.dataGridView1.Rows[i].Cells[z + 2].Value);
                    }
                    break;
                default:
                    break;
            }
        }

        private void Drawing(float[][] wm, float[,] mas, List<float[]> cp, float w)
        {
            //Циклограмма
            GraphPane pane = zg[0].GraphPane;
            PointPairList list;
            LineItem myCurve;
            pane.CurveList.Clear();
            for (int i = 0; i < p; i++)
            {
                list = new PointPairList();
                for (int j = 0; j <= z; j++)
                    list.Add(mas[i, j], j);
                myCurve = pane.AddCurve(so.dataGridView1[0, i].Value.ToString(), list, Color.Blue, SymbolType.None);
                myCurve.Line.Width = 1.6f;
            }
            if (so.toolStripComboBox1.SelectedIndex != 0)
                foreach (var a in cp)
                {
                    list = new PointPairList();
                    list.Add(a[0], a[1]);
                    list.Add(a[0], a[1] + 1);
                    myCurve = pane.AddCurve("Критическое сближение", list, Color.Red, SymbolType.None);
                    myCurve.Line.Style = System.Drawing.Drawing2D.DashStyle.Custom;
                    myCurve.Line.DashOff = 2;
                    myCurve.Line.DashOn = 3;
                    myCurve.Line.Width = 2f;
                }
            zg[0].AxisChange();
            zg[0].Invalidate();
            //Рабочая сила
            pane = zg[1].GraphPane;
            pane.CurveList.Clear();

            list = new PointPairList();
            list.Add(0, Math.Round(w, 3));
            list.Add(mas[p - 1, z], Math.Round(w, 3));
            myCurve = pane.AddCurve("Среднее число рабочих", list, Color.Red, SymbolType.None);
            myCurve.Line.Style = System.Drawing.Drawing2D.DashStyle.Custom;
            myCurve.Line.DashOff = 2;
            myCurve.Line.DashOn = 3;
            myCurve.Line.Width = 2f;

            list = new PointPairList();
            for (int i = 0; i < p * 2 - 1; i++)
            {
                if (wm[0][i] != wm[0][i + 1])
                {
                    list.Add(wm[0][i], wm[1][i]);
                    list.Add(wm[0][i + 1], wm[1][i]);
                }
            }
            myCurve = pane.AddCurve("Workers", list, Color.Blue, SymbolType.None);
            myCurve.Line.Fill = new ZedGraph.Fill(Color.LimeGreen);

            zg[1].AxisChange();
            zg[1].Invalidate();
            //Деньги
            pane = zg[2].GraphPane;
            list = new PointPairList();
            pane.CurveList.Clear();
            for (int i = 0; i < p * 2; i++)
            {
                list.Add(wm[0][i], Math.Round(wm[2][i], 2));
            }
            myCurve = pane.AddCurve("Cash", list, Color.Blue, SymbolType.None);
            myCurve.Line.Width = 1.6f;
            //myCurve.Symbol.Size = 4f;
            //myCurve.Symbol.Border.Width = 1.6f;
            zg[2].AxisChange();
            zg[2].Invalidate();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            toolStripMenuItem1_Click(null, null);
        }

        private void outAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Form childForm in MdiChildren)
            {
                childForm.Close();
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveAsToolStripMenuItem_Click(null, null);
        }

        private void exportStripMenuItem_Click(object sender, EventArgs e)
        {
            if (changed)
                MessageBox.Show("Выполните расчёт и повторите попытку.", "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
            {
                SaveGraph sg = new SaveGraph(zg);
                sg.ShowDialog(this);
            }
        }

        private void fasterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (so.toolStripComboBox1.SelectedIndex != 2)
                MessageBox.Show("Доступно только для неритмичного потока.", "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else if (z > 11)
                MessageBox.Show("Ограничено до 11 захваток.", "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            //else if (changed)
            //MessageBox.Show("Выполните расчёт и повторите попытку.", "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
            {
                solver solv = new solver();
                var cp = new List<float[]>();
                int[] tarr = new int[z];
                string[] seq = new string[z];
                float srok, w;
                float[,] mas = new float[p, z + 1];
                float[,] day = new float[p, z + 1];
                float[][] wm = new float[3][] { new float[p * 2], new float[p * 2], new float[p * 2] };

                for (int i = 0; i < z; i++)
                    seq[i] = so.dataGridView1.Columns[i + 1].HeaderText;
                ToMassiv(ref day, ref wm);
                srok = solv.matrix(day);
                solv.faster(ref day, ref tarr);
                solv.matrix(day, ref mas, ref cp);
                w = solv.workers(ref wm, mas);
                Drawing(wm, mas, cp, w);
                toolStripStatusLabel.Text = String.Format("Общая продолжительность {0} дней. Сокращено на {1} дней.", mas[p - 1, z], srok - mas[p - 1, z]);

                for (int i = 0; i < z; i++)
                {
                    so.dataGridView1.Columns[i + 1].HeaderText = seq[tarr[i]];
                    for (int j = 0; j < p; j++)
                        so.dataGridView1[i + 1, j].Value = day[j, i];
                }
                toolStripSplitButton1.Enabled = true;
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            POSProgram.about ab = new POSProgram.about();
            ab.ShowDialog(this);
        }

        private void toolStripSplitButton1_ButtonClick(object sender, EventArgs e)
        {
            float[,] day = new float[p, z + 1];
            int[] seq = new int[z];

            for (int i = 0; i < z; i++)
            {
                seq[i] = int.Parse(so.dataGridView1.Columns[i + 1].HeaderText);
                for (int j = 0; j < p; j++)
                    day[j, i] = float.Parse(so.dataGridView1[i + 1, j].Value.ToString());
            }
            for (int i = 0; i < z; i++)
            {
                so.dataGridView1.Columns[i + 1].HeaderText = (i + 1).ToString();
                for (int j = 0; j < p; j++)
                    so.dataGridView1[seq[i], j].Value = day[j, i];
            }
            toolStripSplitButton1.Enabled = false;
            toolStripMenuItem1_Click(null, null);
        }
    }
}

/*
 * Справка
 * Прогресс сокращения
 * Перекомпиляция ZedGraph
 */